/******************************************************************************************************
Copyright (C) 2015 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************************/

/*globals Application, nmr, SpectrumRegion, Peaks, qsTr, MnUi, mainWindow, NMRProcessing, NMRSpectrum, FileDialog, File, TextStream, Dir, settings*/
/*jslint plusplus: true, indent: 4*/

///////////////////ENGINE START IMPLEMENTATION/////////////
function SnrPeakCalculator(aParameters) {
	'use strict';

	var horizontalUnits, verticalUnits, badParameters = false;

	//Attributes
	this.parameters = aParameters;
	this.logDetail = "";
	this.status = false;
	this.logLevel = 1; //0: INFO; 1: ERROR; 2: INFO & ERROR
	this.minimumPointsInRegionForAutomaticNoise = 128;
	this.defaultPointsInRegionForAutomaticNoise = 1024;

	//Constructor management
	try {
		if (aParameters === undefined) {
			this.logDetail += "[ERROR]: The parameter object doesn't exist. You have to send the parameters object to the engine's constructor\n";
			badParameters = true;
		} else {

			if (aParameters.automaticNoise !== undefined && typeof (aParameters.automaticNoise) !== "boolean") {
				this.logDetail += "[ERROR]: Parameter automatic noise: " + aParameters.automaticNoise + " must be boolean. Only either true or false value is valid\n";
				badParameters = true;

			} else if (!aParameters.automaticNoise && aParameters.spectrum.dimCount === 1) {
				if (aParameters.noiseStartX === undefined || aParameters.noiseStartX === "") {
					this.logDetail += "[ERROR]: You have to specify the noise start X parameter\n";
					badParameters = true;
				}

				if (isNaN(aParameters.noiseStartX)) {
					this.logDetail += "[ERROR]: Parameter noise start X:" + aParameters.noiseStartX + " must be a number\n";
					badParameters = true;
				}

				if (aParameters.noiseEndX === undefined || aParameters.noiseEndX === "") {
					this.logDetail += "[ERROR]: You have to specify the noise end X parameter\n";
					badParameters = true;
				}

				if (isNaN(aParameters.noiseEndX)) {
					this.logDetail += "[ERROR]: Parameter noise end X: " + aParameters.noiseEndX + " must be a number\n";
					badParameters = true;
				}

				if (aParameters.useMedianInAutomaticNoise !== undefined && typeof (aParameters.useMedianInAutomaticNoise) !== "boolean") {
					this.logDetail += "[ERROR]: Parameter use median in automatic noise: " + aParameters.useMedianInAutomaticNoise + " must be boolean. Only either true or false value is valid\n";
				}

			} else if (aParameters.automaticNoise && aParameters.spectrum.dimCount > 1) {
				this.logDetail += "[ERROR]: The automatic noise feature is only available for 1D spectrum\n";
				badParameters = true;
			} else {
				if (aParameters.minimumPointsInRegionForAutomaticNoise !== undefined) {
					if (isNaN(aParameters.minimumPointsInRegionForAutomaticNoise)) {
						this.logDetail += "[ERROR]: Parameter minimum points in region:" + aParameters.minimumPointsInRegionForAutomaticNoise + " must be a number\n";
						badParameters = true;
					} else {
						this.minimumPointsInRegionForAutomaticNoise = aParameters.minimumPointsInRegionForAutomaticNoise;
					}
				} else {
					if (aParameters.pointsInRegionForAutomaticNoise !== undefined) {
						if (isNaN(aParameters.pointsInRegionForAutomaticNoise)) {
							this.logDetail += "[ERROR]: Parameter points in region for automatic noise:" + aParameters.pointsInRegionForAutomaticNoise + " must be a number\n";
							badParameters = true;
						} else {
							this.pointsInRegionForAutomaticNoise = aParameters.pointsInRegionForAutomaticNoise;
						}
					} else {
						this.pointsInRegionForAutomaticNoise = this.defaultPointsInRegionForAutomaticNoise;
					}
				}
			}

			if (aParameters.signalStartX === undefined || aParameters.signalStartX === "") {
				this.logDetail += "[ERROR]: You have to specify the signal start X parameter\n";
				badParameters = true;
			}

			if (isNaN(aParameters.signalStartX)) {
				this.logDetail += "[ERROR]: Parameter signal start X:" + aParameters.signalStartX + " must be a number\n";
				badParameters = true;
			}

			if (aParameters.signalEndX === undefined || aParameters.signalEndX === "") {
				this.logDetail += "[ERROR]: You have to specify the signal end X parameter\n";
				badParameters = true;
			}

			if (isNaN(aParameters.signalEndX)) {
				this.logDetail += "[ERROR]: Parameter signal end X: " + aParameters.signalEndX + " must be a number\n";
				badParameters = true;
			}

			if (aParameters.apply === undefined || aParameters.apply === "") {
				this.logDetail += "You have to specify the apply parameter by using a number between 0 and 2.\n0 for 1D spectrum, 1 for 2D spectrum, and 2 for 1D and 2D spectra\n";
				badParameters = true;
			}

			if (isNaN(aParameters.apply)) {
				this.logDetail += "[ERROR]: Parameter apply spectrum: " + aParameters.apply + " must be a number between 0 and 2.\n0 for 1D spectrum, 1 for 2D spectrum, and 2 for 1D and 2D spectra\n";
				badParameters = true;
			}

			if (aParameters.apply < 0 && aParameters.apply > 2) {
				this.logDetail += "[ERROR]: You have to specify the apply parameter by using a number between 0 and 2.\n0 for 1D spectrum, 1 for 2D spectrum, and 2 for 1D and 2D spectra\n";
				badParameters = true;
			}

			//We check Y axis if is really necessary.
			if (aParameters.apply !== undefined && aParameters.apply !== "" && aParameters.apply > 0 && aParameters.apply < 3) {
				if (aParameters.noiseStartY === undefined || aParameters.noiseStartY === "") {
					this.logDetail += "[ERROR]: You have to specify the noise start Y parameter\n";
					badParameters = true;
				}

				if (isNaN(aParameters.noiseStartY)) {
					this.logDetail += "[ERROR]: Parameter noise start Y:" + aParameters.noiseStartY + " must be a number\n";
					badParameters = true;
				}

				if (aParameters.noiseEndY === undefined || aParameters.noiseEndY === "") {
					this.logDetail += "[ERROR]: You have to specify the noise end Y parameter\n";
					badParameters = true;
				}

				if (isNaN(aParameters.noiseEndY)) {
					this.logDetail += "[ERROR]: Parameter noise end Y: " + aParameters.noiseEndY + " must be a number\n";
					badParameters = true;
				}

				if (aParameters.signalStartY === undefined || aParameters.signalStartY === "") {
					this.logDetail += "[ERROR]: You have to specify the signal start Y parameter\n";
					badParameters = true;
				}

				if (isNaN(aParameters.signalStartY)) {
					this.logDetail += "[ERROR]: Parameter signal start Y:" + aParameters.signalStartY + " must be a number\n";
					badParameters = true;
				}

				if (aParameters.signalEndY === undefined || aParameters.signalEndY === "") {
					this.logDetail += "[ERROR]: You have to specify the signal end Y parameter\n";
					badParameters = true;
				}

				if (isNaN(aParameters.signalEndY)) {
					this.logDetail += "[ERROR]: Parameter signal end Y: " + aParameters.signalEndY + " must be a number\n";
					badParameters = true;
				}
			}

			//Spectrum control errors
			if (aParameters.spectrum === undefined || aParameters.spectrum.uuid === undefined) {
				this.logDetail += "[ERROR]: An NMR spectrum is required to perform the analysis\n";
				badParameters = true;
			} else if (aParameters.spectrum.toString().indexOf("TNMRSpectrumWrapper") === -1 || aParameters.spectrum instanceof String) {
				this.logDetail += "[ERROR]: The spectrum is not an NMRSpectrum object\n";
				badParameters = true;
			} else if (!aParameters.spectrum.isValid()) {
				this.logDetail += "[ERROR]: The spectrum is not valid\n" + aParameters.spectrum.toString();
				badParameters = true;
			}

			if (aParameters.logLevel !== undefined && aParameters.logLevel >= 0 && aParameters.logLevel <= 2) {
				this.logLevel = aParameters.logLevel;
			}
		}

		//Create an instance of main class and we call the methods following the agreed workflow
		if (!badParameters) {

			//We ensure we always work in ppm internally. We do not check this from the Non_Interactive script because these parameters will always sent in ppm
			if (aParameters.viewer === undefined || (aParameters.viewer !== undefined && !aParameters.viewer)) {
				horizontalUnits = aParameters.spectrum.getProperty("axes.horizontal.units").toString().toLowerCase();
				verticalUnits = aParameters.spectrum.getProperty("axes.vertical.units").toString().toLowerCase();
				if (horizontalUnits !== "unknown" && horizontalUnits !== "ppm") {
					this.parameters.noiseStartX = Number(aParameters.spectrum.unitsToUnits(horizontalUnits, "ppm", aParameters.noiseStartX, aParameters.spectrum.dimCount));
					this.parameters.noiseEndX = Number(aParameters.spectrum.unitsToUnits(horizontalUnits, "ppm", aParameters.noiseEndX, aParameters.spectrum.dimCount));
					this.parameters.signalStartX = Number(aParameters.spectrum.unitsToUnits(horizontalUnits, "ppm", aParameters.signalStartX, aParameters.spectrum.dimCount));
					this.parameters.signalEndX = Number(aParameters.spectrum.unitsToUnits(horizontalUnits, "ppm", aParameters.signalEndX, aParameters.spectrum.dimCount));
				}
				if (aParameters.spectrum.dimCount === 2 && verticalUnits !== "unknown" && verticalUnits !== "ppm") {
					this.parameters.noiseStartY = Number(aParameters.spectrum.unitsToUnits(verticalUnits, "ppm", aParameters.noiseStartY, 1));
					this.parameters.noiseEndY = Number(aParameters.spectrum.unitsToUnits(verticalUnits, "ppm", aParameters.noiseEndY, 1));
					this.parameters.signalStartY = Number(aParameters.spectrum.unitsToUnits(verticalUnits, "ppm", aParameters.signalStartY, 1));
					this.parameters.signalEndY = Number(aParameters.spectrum.unitsToUnits(verticalUnits, "ppm", aParameters.signalEndY, 1));
				}
			}

			//Update status and log
			this.logDetail += "[INFO]: The parameters have been received successfully\n";
			this.status = true;
		}
	} catch (err) {
		this.logDetail += "\nException found during the process. [ERROR]: The detail of the exception is: " + err + "\n";
	}

	//*************Instance Methods Class Engine******************
	SnrPeakCalculator.prototype.checkLimitsRegions = function (aSpectrum, aNoiseLimits, aSignalLimits, aOriginalLimits, aAutomaticNoise, aSNRCalculatorViewer) {
		var errorsFound = false;

		if (aSNRCalculatorViewer === undefined || !aSNRCalculatorViewer) {
			//Check that the region noise selected by user doesn't be greater than the whole spectrum region.
			if (aNoiseLimits.fromX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise start X is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.fromX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise start X is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end X is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end X is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}

			//Since automatic noise feature is only available for 1D spectra, we only check this case
			if (aAutomaticNoise === undefined || !aAutomaticNoise) {
				if (aNoiseLimits.fromY < aOriginalLimits.fromY) {
					this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise start Y is lower than the lowest point of the Y axis spectrum region limit\n";
					errorsFound = true;
				}
				if (aNoiseLimits.fromY > aOriginalLimits.toY) {
					this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise start Y is greater than the greatest point of the Y axis spectrum region limit\n";
					errorsFound = true;
				}
				if (aNoiseLimits.toY > aOriginalLimits.toY) {
					this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end Y is greater than the greatest point of the Y axis spectrum region limit\n";
					errorsFound = true;
				}
				if (aNoiseLimits.toY < aOriginalLimits.fromY) {
					this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end Y is lower than the lowest point of the Y axis spectrum region limit\n";
					errorsFound = true;
				}
			}

			//Signal checking
			if (aSignalLimits.fromX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal start X is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.fromX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal start X is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end X is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end X is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.fromY < aOriginalLimits.fromY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal start Y is lower than the lowest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.fromY > aOriginalLimits.toY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal start Y is greater than the greatest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toY > aOriginalLimits.toY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end Y is greater than the greatest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toY < aOriginalLimits.fromY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end Y is lower than the lowest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
		} else if (aSpectrum.dimCount === 1) {

			//Noise checking for 1D spectra in SnrPeakCalculatorViewer
			if (aNoiseLimits.fromX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise from value, in f1 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.fromX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise from value, in f1 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end value, in f1 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end value, in f1 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}

			//Signal checking for 1D spectra in SnrPeakCalculatorViewer
			if (aSignalLimits.fromX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal from value, in f1 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.fromX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal from value, in f1 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end value, in f1 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end value, in f1 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
		} else {

			//Noise checking for 2D spectra in SnrPeakCalculatorViewer
			if (aNoiseLimits.fromX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise from value, in f2 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.fromX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise from value, in f2 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end value, in f2 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end value, in f2 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}

			if (aNoiseLimits.fromY < aOriginalLimits.fromY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise from value, in f1 dim, is lower than the lowest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.fromY > aOriginalLimits.toY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise fron value, in f1 dim, is greater than the greatest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toY > aOriginalLimits.toY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end value, in f1 dim, is greater than the greatest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aNoiseLimits.toY < aOriginalLimits.fromY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The noise end value, in f1 dim, is lower than the lowest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}

			//Signal checking for 2D spectra in SnrPeakCalculatorViewer
			if (aSignalLimits.fromX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal from value, in f2 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.fromX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal from value, in f2 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toX > aOriginalLimits.toX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end value, in f2 dim, is greater than the greatest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toX < aOriginalLimits.fromX) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end value, in f2 dim, is lower than the lowest point of the X axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.fromY < aOriginalLimits.fromY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal from value, in f1 dim, is lower than the lowest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.fromY > aOriginalLimits.toY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal from value, in f1 dim, is greater than the greatest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toY > aOriginalLimits.toY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end value, in f1 dim, is greater than the greatest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
			if (aSignalLimits.toY < aOriginalLimits.fromY) {
				this.logDetail += "[ERROR]: Error related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum. The signal end value, in f1 dim, is lower than the lowest point of the Y axis spectrum region limit\n";
				errorsFound = true;
			}
		}

		if (errorsFound) {
			return false;
		}

		this.logDetail += "[INFO]: All the parameters defined by the user are between the whole spectrum region related to the " + aSpectrum.experimentType + "_" + aSpectrum.getParam("Pulse Sequence") + " spectrum\n";
		return true;
	};

	SnrPeakCalculator.prototype.getMean = function (aPoints) {
		var i, sum = 0;

		for (i = 0; i < aPoints.length; i++) {
			sum += aPoints[i];
		}

		return (sum / aPoints.length);
	};

	SnrPeakCalculator.prototype.calculateMedianAndMinimum = function (aArray, aMinimum) {
		var result, half, totalElements;

		aArray.sort(function (a, b) { return a.rms - b.rms; });

		//It uses the minimum function
		if (aMinimum !== undefined && aMinimum) {
			result = aArray[0];
		} else {
			//It calculates the median
			totalElements = aArray.length;
			half =  Math.floor(totalElements / 2);
			if (totalElements % 2) {
				result = aArray[half];
			} else {
				result = aArray[half];
				if (aArray[half - 1].rms < aArray[half].rms) {
					result = aArray[half - 1];
				}
			}
		}

		return result;
	};

	SnrPeakCalculator.prototype.getPointsInRegion = function (aSpectrum, aRegion) {
		var i, j, fromX, toX, fromY, toY, points = [];

		if (aSpectrum.dimCount === 1) {

			fromX = aRegion.from(1);
			toX = aRegion.to(1);

			fromX = Math.round(aSpectrum.unitsToUnits("ppm", "pt", fromX, 1));
			toX = Math.round(aSpectrum.unitsToUnits("ppm", "pt", toX, 1));

			for (i = fromX; i <= toX; i++) {
				points.push(aSpectrum.real(i));
			}

		} else {

			fromX = aRegion.from(2);
			toX = aRegion.to(2);
			fromY = aRegion.from(1);
			toY = aRegion.to(1);

			fromX = Math.round(aSpectrum.unitsToUnits("ppm", "pt", fromX, 2));
			toX = Math.round(aSpectrum.unitsToUnits("ppm", "pt", toX, 2));
			fromY = Math.round(aSpectrum.unitsToUnits("ppm", "pt", fromY, 1));
			toY = Math.round(aSpectrum.unitsToUnits("ppm", "pt", toY, 1));

			for (i = Math.min(fromX, toX); i <= Math.max(fromX, toX); i++) {
				for (j = Math.min(fromY, toY); j <= Math.max(fromY, toY); j++) {
					points.push(aSpectrum.real(j, i));
				}
			}
		}

		return points;
	};

	SnrPeakCalculator.prototype.calculateNoiseForPoints = function (aPoints) {
		//algorithm from http://triton.iqfr.csic.es/guide/nmr/smanual/10_4_anal.html
		//The noise value is tolerant to linear baseline distortions within the region
		var N, N2, i, Y, Y2, XY, noise;
		if (aPoints.length % 2) {
			aPoints.pop();
		}
		N = aPoints.length;
		N2 = aPoints.length / 2;
		Y = 0.0;
		Y2 = 0.0;
		XY = 0.0;
		for (i = 0; i < N; i++) {
			Y += aPoints[i];
			Y2 += aPoints[i] * aPoints[i];
		}
		for (i = N2; i < N; i++) {
			XY += (i - N2 + 1) * (aPoints[i] - aPoints[N - i - 1]);
		}
		noise = Math.sqrt((Y2 - (Y * Y + 3 * XY * XY / (N * N - 1)) / N) / (N - 1));
		return noise;
	};

	SnrPeakCalculator.prototype.calculateNoise = function (aSpectrum, aRegion, aMedianFunction) {
		var i, j, noise, currentRegion, noiseArray, useMinimum, pointsInRegion, flagRegionFound;

		//Initliaze vars
		pointsInRegion = [];

		//Noise for a single region. This part will be used by the manual noise feature.
		if (aRegion.length === undefined || aRegion.length === 0) {
			pointsInRegion = this.getPointsInRegion(aSpectrum, aRegion);
			noise = this.calculateNoiseForPoints(pointsInRegion);

		//Noise for an array of regions, needed by the automatic noise feature
		} else {
			//Get the RMS (root mean square) for each noise region
			noiseArray = [];
			flagRegionFound = false;

			//We use a dynamic auto-threshold if the minimumPointsInRegions is not defined in the parameters.
			if (this.pointsInRegionForAutomaticNoise !== undefined) {
				//We stop either we reach 128 or we have found at least a region
				for (i = this.pointsInRegionForAutomaticNoise; i >= this.minimumPointsInRegionForAutomaticNoise && !flagRegionFound; i--) {
					flagRegionFound = false;
					for (j = 0; j < aRegion.length; j++) {
						currentRegion = aRegion[j];
						pointsInRegion = this.getPointsInRegion(aSpectrum, currentRegion);
						if (pointsInRegion.length >= i) {
							noiseArray.push({});
							noiseArray[noiseArray.length - 1].from = currentRegion.from(1);
							noiseArray[noiseArray.length - 1].to = currentRegion.to(1);
							noiseArray[noiseArray.length - 1].rms = this.calculateNoiseForPoints(pointsInRegion);
							flagRegionFound = true;
						}
					}
				}
			//This behaviour will be applied if the minimumPointsInRegionForAutomaticNoise was sent and correctly defined whithin the parameters
			//Something which occurs with the SnrPeakCalculator viewer if both the automatic noise is enabled and the minimum feature is checked
			} else {
				for (i = 0; i < aRegion.length; i++) {
					currentRegion = aRegion[i];
					pointsInRegion = this.getPointsInRegion(aSpectrum, currentRegion);
					if (pointsInRegion.length >= this.minimumPointsInRegionForAutomaticNoise) {
						noiseArray.push({});
						noiseArray[noiseArray.length - 1].from = currentRegion.from(1);
						noiseArray[noiseArray.length - 1].to = currentRegion.to(1);
						noiseArray[noiseArray.length - 1].rms = this.calculateNoiseForPoints(pointsInRegion);
					}
				}
			}

			//We use always the minimum function because the noise number can only be made bigger by interference, tiny peaks, bad phase...
			if (noiseArray.length >= 3) {
				useMinimum = true;
				if (aMedianFunction !== undefined && aMedianFunction) {
					useMinimum = false;
				}
				noise = this.calculateMedianAndMinimum(noiseArray, useMinimum);
			} else if (noiseArray.length === 2) {
				noise = noiseArray[0];
				if (noiseArray[1].rms < noiseArray[0].rms) {
					noise = noiseArray[1];
				}
			} else if (noiseArray.length === 1) {
				noise = noiseArray[0];
			}
		}

		return noise;
	};

	SnrPeakCalculator.prototype.getOldPeaks = function (aSpectrum) {
		var oldPeaks;

		//Return the spectrum peaks
		oldPeaks = new Peaks(aSpectrum.peaks());
		return oldPeaks;
	};

	SnrPeakCalculator.prototype.appendPeaksRegionToSpectrum = function (aSpectrum, aPeaksInRegion) {
		var i;

		//Append the peaks in region to spectrum
		for (i = 0; i < aPeaksInRegion.count; i++) {
			aSpectrum.peaks().append(aPeaksInRegion.at(i));
		}
	};

	SnrPeakCalculator.prototype.makeAutomaticPeakPicking = function (aSpectrum) {
		var nmrProcessing;

		nmrProcessing = new NMRProcessing(aSpectrum.proc);
		nmrProcessing.setParameter("PP.AutoClassify", false);
		nmrProcessing.setParameter("PP.Method", "Standard");
		nmrProcessing.setParameter("PP.Apply", true);
		aSpectrum.setProperty("peaks.show", false);
		aSpectrum.process(nmrProcessing);
		aSpectrum.update();
	};

	SnrPeakCalculator.prototype.getPeaksSpectrumBelongToRegion = function (aPeaksInRegion, aPeaksInSpectrum) {
		var i, j, found, positionsToDelete = [];

		//Get the positions peak which don't belong to the regions selected by the user
		for (i = 0; i < aPeaksInSpectrum.count; i++) {
			found = false;
			for (j = 0; j < aPeaksInRegion.count && !found; j++) {
				if (aPeaksInSpectrum.at(i).id === aPeaksInRegion.at(j).id) {
					found = true;
				}
			}
			if (!found) {
				positionsToDelete.push(i);
			}
		}

		//Sort descending the array and we delete all the element which doesn't belong to the region
		positionsToDelete.sort(function (a, b) {return b - a; });
		for (i = 0; i < positionsToDelete.length; i++) {
			aPeaksInSpectrum.removeAt(positionsToDelete[i]);
		}
	};

	SnrPeakCalculator.prototype.calculateSNRPeaks = function (aSpectrum, aPeaksInRegion, aPeaksInSpectrum, aNoise) {
		var i, oldAnnotation, snrIndex;

		for (i = 0; i < aPeaksInRegion.count; i++) {
			oldAnnotation = aPeaksInSpectrum.byId(aPeaksInRegion.at(i).id).annotation;
			snrIndex = oldAnnotation.indexOf("SNR:");
			if (snrIndex !== -1) {
				oldAnnotation = oldAnnotation.slice(0, snrIndex);
			}
			aPeaksInSpectrum.byId(aPeaksInRegion.at(i).id).annotation = oldAnnotation + "SNR: " + (aPeaksInRegion.at(i).intensity / (2.0 * aNoise)).toFixed(2);
		}
		aSpectrum.setPeaks(aPeaksInSpectrum);
		aSpectrum.setProperty("peaks.show", true);
		aSpectrum.update();
		mainWindow.activeDocument.update();
	};

	SnrPeakCalculator.prototype.invert1DRegions = function (aLowestLimit, aHighestLimit, aRegionsArray) {
		var i, result, from, to, aux;

		result = [];
		if (aHighestLimit < aLowestLimit) {
			aux = aHighestLimit;
			aLowestLimit = aHighestLimit;
			to = aHighestLimit;
		}

		//If there is no regions into the array, then the whole region will be taken as single region
		if (aRegionsArray === undefined || aRegionsArray.length === undefined || aRegionsArray.length < 1) {
			result.push(new SpectrumRegion(aLowestLimit, aHighestLimit));
		} else {
			//This algorithm only works if the regions are in ascent order.
			aRegionsArray.sort(function (a, b) { return a.from - b.from; });
			for (i = 0; i < aRegionsArray.length; i++) {
				from = Number(aRegionsArray[i].from);
				to = Number(aRegionsArray[i].to);
				if (to < from) {
					aux = to;
					from = to;
					to = aux;
				}
				if (i === 0) {
					result.push(new SpectrumRegion(aLowestLimit, from));
				}
				if (i !== aRegionsArray.length - 1) {
					from = Number(aRegionsArray[i + 1].from);
					if (from < to) {
						aux = from;
						to = from;
						from = aux;
					}
					result.push(new SpectrumRegion(to, from));
				} else {
					from = Number(aRegionsArray[i].to);
					result.push(new SpectrumRegion(from, aHighestLimit));
				}
			}
		}

		return result;
	};

	SnrPeakCalculator.prototype.manageLimitsOverlapping = function (aObjectLimits) {
		var aux;

		if (aObjectLimits.fromX !== undefined && aObjectLimits.toX !== undefined) {
			if (Number(aObjectLimits.fromX) > Number(aObjectLimits.toX)) {
				aux = aObjectLimits.toX;
				aObjectLimits.toX = aObjectLimits.fromX;
				aObjectLimits.fromX = aux;
			}
		}

		if (aObjectLimits.fromY !== undefined && aObjectLimits.toY !== undefined) {
			if (Number(aObjectLimits.fromY) > Number(aObjectLimits.toY)) {
				aux = aObjectLimits.toY;
				aObjectLimits.toY = aObjectLimits.fromY;
				aObjectLimits.fromY = aux;
			}
		}
	};

	SnrPeakCalculator.prototype.process = function () {
		var spectrum, originalLimits, noiseLimits = {}, signalLimits = {}, noiseRegion, signalRegion, peaksInRegion, isViewer, zoomLimits,
			peaksInSpectrum, noise, oldPeaks, currentPeakPickingMethod, verticalUnits, horizontalUnits, ppmFrom, ppmTo, aux, noiseRegions,
			maxPPMAutomaticRegion, minPPMAutomaticRegion, loopIndex, currentFromPPM, currentToPPM, auxRegions, isInteractive;

		//Abort execution if parameters are not correct
		if (!this.status) {
			this.logDetail += "[ERROR]: The parameters sent to the class constructor are not valid.\n";
			this.status = false;

		} else {
			try {

				//Get the spectrum noise region
				spectrum = this.parameters.spectrum;
				isViewer = this.parameters.viewer;
				isInteractive = this.parameters.interactive;

				//Get the current peak peacking method and change to standard method
				currentPeakPickingMethod = SnrPeakCalculator.getPeakPickingMethod(spectrum);
				SnrPeakCalculator.setPeakPickingMethod(spectrum, "Standard");

				//Abort the process if the dimension are not enabled for the spectrum dimension
				if (spectrum.dimCount === 1 && !(this.parameters.apply === 0 || this.parameters.apply === 2)) {
					this.logDetail += "[INFO]: The " + spectrum.experimentType + "_" + spectrum.getParam("Pulse Sequence") + " spectrum will not be process because of its dimension is not applied\n";
					this.status = false;
					return;
				}
				if (spectrum.dimCount === 2 && (this.parameters.apply < 1)) {
					this.logDetail += "[INFO]: The " + spectrum.experimentType + "_" + spectrum.getParam("Pulse Sequence") + " spectrum will not be process because of its dimension is not applied\n";
					this.status = false;
					return;
				}

				//Recieve the originalLimits if it has been sent
				if (this.parameters.originalLimits !== undefined) {
					originalLimits = this.parameters.originalLimits;
				} else {

					//Internally we always work in PPM
					originalLimits = spectrum.getFullScaleLimits();
					verticalUnits = spectrum.getProperty("axes.vertical.units").toString().toLowerCase();
					horizontalUnits = spectrum.getProperty("axes.horizontal.units").toString().toLowerCase();
					ppmFrom = spectrum.unitsToUnits(horizontalUnits, "ppm", originalLimits.fromX, spectrum.dimCount);
					ppmTo = spectrum.unitsToUnits(horizontalUnits, "ppm", originalLimits.toX, spectrum.dimCount);
					originalLimits.fromX = Number(ppmFrom);
					originalLimits.toX = Number(ppmTo);
					if (spectrum.dimCount === 2 && verticalUnits !== "unknown") {
						ppmFrom = spectrum.unitsToUnits(verticalUnits, "ppm", originalLimits.fromY, 1);
						ppmTo = spectrum.unitsToUnits(verticalUnits, "ppm", originalLimits.toY, 1);
						originalLimits.fromY = Number(ppmFrom);
						originalLimits.toY = Number(ppmTo);
					}
				}
				signalLimits.fromX = Number(this.parameters.signalStartX);
				signalLimits.toX = Number(this.parameters.signalEndX);
				signalLimits.fromY = Number(this.parameters.signalStartY);
				signalLimits.toY = Number(this.parameters.signalEndY);

				if (aParameters.automaticNoise === undefined || !aParameters.automaticNoise) {

					noiseLimits.fromX = Number(this.parameters.noiseStartX);
					noiseLimits.toX = Number(this.parameters.noiseEndX);
					noiseLimits.fromY = Number(this.parameters.noiseStartY);
					noiseLimits.toY = Number(this.parameters.noiseEndY);

					this.manageLimitsOverlapping(originalLimits);
					this.manageLimitsOverlapping(signalLimits);
					this.manageLimitsOverlapping(noiseLimits);

					//Check limits for regions
					if (!this.checkLimitsRegions(spectrum, noiseLimits, signalLimits, originalLimits, undefined, isViewer)) {
						this.status = false;
						return;
					}

					//Instance the noise SpectrumRegion by using the noise limits given by user.
					if (spectrum.dimCount === 1 && (this.parameters.apply === 0 || this.parameters.apply === 2)) {
						noiseRegion = new SpectrumRegion(noiseLimits.fromX, noiseLimits.toX);
					} else if (spectrum.dimCount === 2 && this.parameters.apply > 0) {
						noiseRegion = new SpectrumRegion(noiseLimits.fromX, noiseLimits.toX, noiseLimits.fromY, noiseLimits.toY);
					}

					//Check problem with noise region
					if (noiseRegion === undefined) {
						this.logDetail += "[ERROR]: Error related to the " + spectrum.experimentType + "_" + spectrum.getParam("Pulse Sequence") + " spectrum. There was a problem setting the noise region.\n";
						this.status = false;
						return;
					}

					//Remove previous peaks only for non-interactive script. The interactive removes itself the old peaks
					if (this.parameters.deleteOldPeaks !== undefined && this.parameters.deleteOldPeaks) {
						SnrPeakCalculator.removeAllPeaks(spectrum);
					}

					//Calculate the noise
					noise = this.calculateNoise(spectrum, noiseRegion);

				} else if (spectrum.dimCount === 1 && aParameters.automaticNoise) {

					//Detect noise free regions automatically by using the noise free regions. Then we invert the ranges
					auxRegions = spectrum.noiseFreeRegions();
					noiseRegions = this.invert1DRegions(originalLimits.fromX, originalLimits.toX, auxRegions);
					if (noiseRegions.length === 0) {
						this.logDetail += "[ERROR]: Error related to the " + spectrum.experimentType + "_" + spectrum.getParam("Pulse Sequence") + " spectrum. Automatic regions feature did not found regions.\n";
						this.status = false;
						return;
					}

					//Get maximum and minimum ppm for checking possible out of bounds limits
					maxPPMAutomaticRegion = noiseRegions[0].from(1);
					minPPMAutomaticRegion = noiseRegions[0].from(1);
					for (loopIndex = 0; loopIndex < noiseRegions.length; loopIndex++) {
						currentFromPPM = noiseRegions[loopIndex].from(1);
						currentToPPM = noiseRegions[loopIndex].to(1);
						if (currentFromPPM < minPPMAutomaticRegion) {
							minPPMAutomaticRegion = currentFromPPM;
						}
						if (currentToPPM < minPPMAutomaticRegion) {
							minPPMAutomaticRegion = currentToPPM;
						}
						if (currentFromPPM > maxPPMAutomaticRegion) {
							maxPPMAutomaticRegion = currentFromPPM;
						}
						if (currentToPPM > maxPPMAutomaticRegion) {
							maxPPMAutomaticRegion = currentToPPM;
						}
					}

					//Define noise limits
					noiseLimits.fromX = Number(minPPMAutomaticRegion);
					noiseLimits.toX = Number(maxPPMAutomaticRegion);
					noiseLimits.fromY = undefined;
					noiseLimits.toY = undefined;

					//Check limits for regions
					if (!this.checkLimitsRegions(spectrum, noiseLimits, signalLimits, originalLimits, true, isViewer)) {
						this.status = false;
						return;
					}

					//Remove previous peaks only for non-interactive script. The interactive removes itself the old peaks
					if (this.parameters.deleteOldPeaks !== undefined && this.parameters.deleteOldPeaks) {
						SnrPeakCalculator.removeAllPeaks(spectrum);
					}

					//Calculate the noise
					this.automaticNoiseResults = this.calculateNoise(spectrum, noiseRegions, this.parameters.useMedianInAutomaticNoise);
					if (this.automaticNoiseResults !== undefined) {
						noise = this.automaticNoiseResults.rms;
					} else {
						this.status = false;
						this.logDetail += "[ERROR]: A noise region having sufficient points could not be found automatically";
						return;
					}
				}

				//Initialize the zoomLimits object to signalLimits values
				zoomLimits = {};
				zoomLimits = signalLimits;

				//Checking for possible rms noise issues
				if (noise === undefined || isNaN(noise)) {
					this.logDetail += "[ERROR]: Error related to the " + spectrum.experimentType + "_" + spectrum.getParam("Pulse Sequence") + " spectrum. There was a problem calculating the RMS of the noise region.\n";
					this.status = false;
					return;
				}

				//Create the signal region
				if (spectrum.dimCount === 1 && (this.parameters.apply === 0 || this.parameters.apply === 2)) {
					signalRegion = new SpectrumRegion(signalLimits.fromX, signalLimits.toX);
				} else if (spectrum.dimCount === 2 && this.parameters.apply > 0) {
					signalRegion = new SpectrumRegion(signalLimits.fromX, signalLimits.toX, signalLimits.fromY, signalLimits.toY);
				}

				//Manage problems with the signal region
				if (signalRegion === undefined) {
					this.logDetail += "[ERROR]: Error related to the " + spectrum.experimentType + "_" + spectrum.getParam("Pulse Sequence") + " spectrum. There was a problem setting the signal region.\n";
				}

				//Keep old peaks for letting work with serveral signal regions.
				oldPeaks = this.getOldPeaks(spectrum);

				//We obtain the region's peaks
				peaksInRegion = new Peaks(spectrum, signalRegion);
				peaksInSpectrum = spectrum.peaks();

				//We make the local peak picking only by non-interactive. Non-interactive is manual peak picking
				if (this.parameters.originalLimits === undefined) {
					this.appendPeaksRegionToSpectrum(spectrum, peaksInRegion);
				}

				//If there aren't peaks, we make the peak picking automatically
				if (peaksInSpectrum.count === 0) {
					this.makeAutomaticPeakPicking(spectrum);
					peaksInRegion = new Peaks(spectrum, signalRegion);
					peaksInSpectrum = spectrum.peaks();
				}

				//Once made the peak picking, we delete all the peaks which don't belong to the signal region
				this.getPeaksSpectrumBelongToRegion(peaksInRegion, peaksInSpectrum);

				//Finally, for the selected peaks, we calculate SNR by mading a new annotation
				this.calculateSNRPeaks(spectrum, peaksInRegion, peaksInSpectrum, noise);

				//Restore previous peaks for working with serveral signal regions
				this.appendPeaksRegionToSpectrum(spectrum, oldPeaks);

				//Fit the the view of the current spectrum to the signal region taking into account the units displayed
				if (isInteractive === undefined || (isInteractive !== undefined && !isInteractive)) {

					//Given that zoom works with the current units we have to convert to the current units if are not ppm
					horizontalUnits = aParameters.spectrum.getProperty("axes.horizontal.units").toString().toLowerCase();
					verticalUnits = aParameters.spectrum.getProperty("axes.vertical.units").toString().toLowerCase();
					if (horizontalUnits !== "unknown" && horizontalUnits !== "ppm") {
						aux = signalLimits.fromX;
						zoomLimits.fromX = Number(spectrum.unitsToUnits("ppm", horizontalUnits, aux, spectrum.dimCount));
						aux = signalLimits.toX;
						zoomLimits.toX = Number(spectrum.unitsToUnits("ppm", horizontalUnits, aux, spectrum.dimCount));
					}

					if (spectrum.dimCount === 2 && verticalUnits !== "unknown" && verticalUnits !== "ppm") {
						aux = signalLimits.fromY;
						zoomLimits.fromY = Number(spectrum.unitsToUnits("ppm", verticalUnits, aux, 1));
						aux = signalLimits.toY;
						zoomLimits.toY = Number(spectrum.unitsToUnits("ppm", verticalUnits, aux, 1));
					}

					//Check the zoom type what is needed to avoid bug found on issue #14471
					if (zoomLimits.fromY === undefined || isNaN(zoomLimits.fromY) || zoomLimits.toY === undefined || isNaN(zoomLimits.toY)) {
						spectrum.horzZoom(zoomLimits.fromX, zoomLimits.toX);
					} else {
						spectrum.zoom(zoomLimits);
					}

					//Fit to height
					spectrum.fitToHeight();
				}
				spectrum.update();
				mainWindow.activeDocument.update();

			} catch (err) {
				this.logDetail += "\nException found during the SNR calculating process. [ERROR]: The detail of the exception is: " + err + "\n";
			} finally {
				//Restore the original peack picking method
				SnrPeakCalculator.setPeakPickingMethod(spectrum, currentPeakPickingMethod);

				//Manage the log by using the detail level wanted.
				switch (this.logLevel) {
				case 0:
					this.logDetail = this.logDetail.replace(new RegExp("^(\\s)*\\[ERROR\\].*\\s", "mg"), "");
					break;
				case 1:
					this.logDetail = this.logDetail.replace(new RegExp("^(\\s)*\\[INFO\\].*\\s", "mg"), "");
					break;
				}
				mainWindow.activeDocument.update();
			}
		}
	};
}
//*************Static Methods Class Engine******************
SnrPeakCalculator.thereIs1D2DItemSelected = function (aDimSpectrum) {
	'use strict';

	var i, totalItemSelected, currentItem, spectrum, dimension, totalSpectra;
	//If argument is false look for a 1D Sepctrum. Otherwise look for 2D Spectrum
	dimension = 1;
	if (aDimSpectrum !== undefined && aDimSpectrum) {
		dimension = 2;
	}

	totalItemSelected = mainWindow.activeDocument.selection().length;
	if (totalItemSelected > 0) {
		for (i = 0; i < totalItemSelected; i++) {
			currentItem = mainWindow.activeDocument.selection()[i];
			if (currentItem.name === "NMR Spectrum") {
				spectrum = new NMRSpectrum(currentItem);
				if (spectrum.dimCount === dimension) {
					return true;
				}
			}
		}
	} else {
		spectrum = nmr.activeSpectrum();
		if (spectrum.uuid === undefined || !spectrum.isValid()) {
			totalSpectra = mainWindow.activeDocument.curPage().itemCount("NMR Spectrum");
			if (totalSpectra > 0) {
				for (i = 0; i < totalSpectra; i++) {
					spectrum = new NMRSpectrum(mainWindow.activeDocument.curPage().item(0, "NMR Spectrum"));
					if (spectrum.uuid !== undefined && spectrum.isValid() && spectrum.dimCount === dimension) {
						return true;
					}
				}
			}
		} else if (spectrum.dimCount === dimension) {
			return true;
		}
	}
	return false;
};

SnrPeakCalculator.thereIsSelected1D2DSpectrum = function (aDimSpectrum) {
	'use strict';

	var totalPageSelected, totalSpectraCurrentPage, currentPage, i, found = false;

	totalPageSelected = mainWindow.activeDocument.selectedPages().length;
	totalSpectraCurrentPage = mainWindow.activeDocument.curPage().itemCount("NMR Spectrum");

	//If there isn't a selected page we work with the current page.
	if (totalPageSelected < 1) {
		if (totalSpectraCurrentPage > 0) {
			//If there isn't a selected item on the current page we get the active spectrum
			return SnrPeakCalculator.thereIs1D2DItemSelected(aDimSpectrum);
		}
	} else {
		for (i = 0; i < totalPageSelected; i++) {
			currentPage = mainWindow.activeDocument.selectedPages()[i];
			mainWindow.activeDocument.setCurPage(currentPage);
			totalSpectraCurrentPage = currentPage.itemCount("NMR Spectrum");
			if (totalSpectraCurrentPage > 0) {
				found = SnrPeakCalculator.thereIs1D2DItemSelected(aDimSpectrum);
				if (found) {
					return true;
				}
			} else if (i === totalPageSelected - 1) {
				return false;
			}
		}
	}
	return false;
};

SnrPeakCalculator.getCurrentPageSpectraSelected = function () {
	'use strict';

	var totalItemSelected, i, currentItem, spectrum, spectraFound = [], totalSpectra, found = false;

	totalItemSelected = mainWindow.activeDocument.selection().length;
	if (totalItemSelected > 0) {
		for (i = 0; i < totalItemSelected; i++) {
			currentItem = mainWindow.activeDocument.selection()[i];
			if (currentItem.name === "NMR Spectrum") {
				spectrum = new NMRSpectrum(currentItem);
				if (spectrum !== undefined) {
					spectraFound.push(spectrum);
				}
			}
		}
	} else {
		spectrum = nmr.activeSpectrum();
		if (spectrum.uuid === undefined || !spectrum.isValid()) {
			totalSpectra = mainWindow.activeDocument.curPage().itemCount("NMR Spectrum");
			if (totalSpectra > 0) {
				for (i = 0; i < totalSpectra && !found; i++) {
					spectrum = new NMRSpectrum(mainWindow.activeDocument.curPage().item(0, "NMR Spectrum"));
					if (spectrum.uuid !== undefined && spectrum.isValid()) {
						found = true;
					}
				}
			}
		}
		spectraFound.push(spectrum);
	}
	return spectraFound;
};

SnrPeakCalculator.getAllSelectedSpectra = function () {
	'use strict';

	var totalPageSelected, totalSpectraCurrentPage, currentPage, i, j, spectraFound = [], auxSpectra = [];

	totalPageSelected = mainWindow.activeDocument.selectedPages().length;
	totalSpectraCurrentPage = mainWindow.activeDocument.curPage().itemCount("NMR Spectrum");

	//If there isn't a selected page we work with the current page.
	if (totalPageSelected < 1) {
		if (totalSpectraCurrentPage > 0) {
			//If there isn't a selected item on the current page we get the active spectrum
			return SnrPeakCalculator.getCurrentPageSpectraSelected();
		}
	} else {
		for (i = 0; i < totalPageSelected; i++) {
			currentPage = mainWindow.activeDocument.selectedPages()[i];
			mainWindow.activeDocument.setCurPage(currentPage);
			totalSpectraCurrentPage = currentPage.itemCount("NMR Spectrum");
			auxSpectra = [];
			if (totalSpectraCurrentPage > 0) {
				auxSpectra = SnrPeakCalculator.getCurrentPageSpectraSelected();
				for (j = 0; j < auxSpectra.length; j++) {
					spectraFound.push(auxSpectra[j]);
				}
			}
		}
	}
	return spectraFound;
};

SnrPeakCalculator.getPeakPickingMethod = function (aSpectrum) {
	'use strict';

	return aSpectrum.proc.getParameter("PP.Method");
};

SnrPeakCalculator.setPeakPickingMethod = function (aSpectrum, aValue) {
	'use strict';

	return aSpectrum.proc.setParameter("PP.Method", aValue);
};

SnrPeakCalculator.removeAllPeaks = function (aSpectrum) {
	'use strict';

	var i, totalPeaks, peaks;

	peaks = aSpectrum.peaks();
	totalPeaks = peaks.count;
	if (totalPeaks > 0) {
		for (i = 0; i < totalPeaks; i++) {
			peaks.removeAt(0);
		}
		aSpectrum.update();
		mainWindow.activeDocument.update();
	}
};
